package com.example.service1.call.controller;

import com.example.service1.common.api.entity.ResponseResult;
import com.example.service1.common.dto.TestDto;
import com.example.service1.common.vo.TestVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;

/**
 * rpc远程调用其他服务器上的服务，通过restful的http请求模板请求api方法
 */
@RestController("rpcController")
@RequestMapping("/rpc")
public class RPCController {

    //http://application的name
    private static final  String SERVICE1_REQ_PATH = "http://service1-app";

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 负载均衡器
     * 可以选择获取指定服务的实例(根据负载均衡算法)，服务实例有ip信息、端口信息等
     */
    @Autowired
    private LoadBalancerClient loadBalancerClient;




    @GetMapping("/post/pathAndBodyArg/hystrix")
    public ResponseResult<TestVo> pathAndBodyArgPostHystrix(){
        HashMap<String, Object> uriMap = new HashMap<>();
        uriMap.put("name","path参数");
        HttpEntity<TestDto> httpEntity  = new HttpEntity<>(TestDto.defaultCreate().setAge(1616L),null);
        ParameterizedTypeReference responseType = new ParameterizedTypeReference<ResponseResult<TestVo>>() {};
        ResponseEntity<ResponseResult<TestVo>> responseEntity = restTemplate.exchange(SERVICE1_REQ_PATH+"/service1/post/pathAndBodyArg/hystrix/{name}",
                HttpMethod.POST,httpEntity,responseType,uriMap);
        return responseEntity.getBody();
    }

    @GetMapping("/get/noArg")
    public ResponseResult<TestVo> rpcNoArgGet(){
        ParameterizedTypeReference responseType = new ParameterizedTypeReference<ResponseResult<TestVo>>() {};
        ResponseEntity<ResponseResult<TestVo>> responseEntity = restTemplate.exchange(SERVICE1_REQ_PATH+"/service1/get/noArg",
                HttpMethod.GET,null,responseType);
        return responseEntity.getBody();
    }

    @GetMapping("/get/pathArg")
    public ResponseResult<TestVo> rpcPathArgGet(){
        ParameterizedTypeReference responseType = new ParameterizedTypeReference<ResponseResult<TestVo>>() {};
        HashMap<String, Object> uriParam = new HashMap<>();
        uriParam.put("name","path参数字符串");
        uriParam.put("date", LocalDate.now());
        ResponseEntity<ResponseResult<TestVo>> responseEntity = restTemplate.exchange(SERVICE1_REQ_PATH+"/service1/get/pathArg/{name}/{date}",
                HttpMethod.GET,null,responseType,uriParam);
        return responseEntity.getBody();
    }

    @GetMapping("/get/pathArg/loadBalancer")
    public ResponseResult<TestVo> rpcPathArgGetLoadBalancer(){
        ParameterizedTypeReference responseType = new ParameterizedTypeReference<ResponseResult<TestVo>>() {};
        HashMap<String, Object> uriParam = new HashMap<>();
        uriParam.put("name","path参数字符串");
        uriParam.put("date", LocalDate.now());
        ServiceInstance instance = loadBalancerClient.choose("service1-app");
        //如果使用这种服务名方式service1-app进行调用，则必须将restTemplate的@LoadBalanced给开启，否则会识别不到
        //这是因为@LoadBalanced会去拉取服务注册中心的服务列表，然后choose负载均衡。
        String url = String.format("http://%s/service1/get/pathArg/{name}/{date}",instance.getServiceId());
        //如果使用这种方式169.254.0.236:8002指定地址调用，则必须将restTemplate的@LoadBalanced给注释掉。
        //这是因为@LoadBalanced相当于再找一次choose方法，就会出现No instances available for 169.254.0.236
//        String url = String.format("http://%s:%s/service1/get/pathArg/{name}/{date}",instance.getHost(),instance.getPort());
        ResponseEntity<ResponseResult<TestVo>> responseEntity = restTemplate.exchange(url,
                HttpMethod.GET,null,responseType,uriParam);
        return responseEntity.getBody();
    }


    @GetMapping("/post/pathAndBodyArg")
    public ResponseResult<TestVo> rpcPathAndBodyArgPost(){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<TestDto> httpEntity  = new HttpEntity<>(TestDto.defaultCreate().setAge(1616L),headers);

        ParameterizedTypeReference responseType = new ParameterizedTypeReference<ResponseResult<TestVo>>() {};
        HashMap<String, Object> uriParam = new HashMap<>();
        uriParam.put("name","path参数字符串");
        uriParam.put("date", LocalDate.now());
        ResponseEntity<ResponseResult<TestVo>> responseEntity = restTemplate.exchange(SERVICE1_REQ_PATH+"/service1/post/pathAndBodyArg/{name}/{date}",
                HttpMethod.POST,httpEntity,responseType,uriParam);
        return responseEntity.getBody();
    }

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/get/allService")
    public ResponseResult<List<ServiceInstance>> getAllService(){
        List<ServiceInstance> list = discoveryClient.getInstances("service1-provider");
        if (list != null && list.size() > 0 ) {
            System.out.println("该实例对应的客户端的主机名："+list.get(0).getHost());
            System.out.println("该实例对应的客户端的端口号："+list.get(0).getPort());
            System.out.println("该实例使用的协议："+list.get(0).getScheme());
            for(ServiceInstance instance:list){
                //http://localhost:8001
                System.out.println("调用的工程上下文URI："+instance.getUri());
                //{management.port=8001}
                System.out.println("与服务实例关联的键/值对元数据："+instance.getMetadata());
            }
        }
        return ResponseResult.success(list);
    }
}
